import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class Document {
	static String line;
	static String[] arrOfStrings;
	static HashSet<String> hashSet;
	static ArrayList<String> arrayList;
	static HashMap<String, Integer> hashMap;
	static int rowCounter = 0, columnCounter = 0;
	static HashMap<String, Integer> rowHashMap = new HashMap<String, Integer>();
	static HashMap<String, Integer> columnHashMap = new HashMap<String, Integer>();
	static HashMap<Integer, Integer> countOfNoOfTrues = new HashMap<Integer, Integer>();

	/* This function will get the frequency of words */
	public static HashMap<String, Integer> getWordfrequency(
			BufferedReader bufferedReader, String fileURL) {
		/* Getting the objects */
		arrayList = new ArrayList<String>();
		hashMap = new HashMap<String, Integer>();

		try {
			/* Getting the first line */
			line = bufferedReader.readLine().trim().replaceAll("\\s+", " ");
			while (true) {
				/* Pruning all the spaces in the line */
				line = line.trim().replaceAll("\\s+", " ");
				/* Splitting the line into strings */
				arrOfStrings = line.split("\\s");
				/* Putting the words into an array list */
				for (String str : arrOfStrings) {
					arrayList.add(str.toLowerCase().replaceAll("\\W", ""));
				}
				/* Getting the next line */
				line = bufferedReader.readLine();
				/* Breaking the loop */
				if (line == null) {
					/* Closing the reader pointer of the file */
					bufferedReader.close();
					break;
				}
			}
		} catch (Exception e) {
		}
		/* List of items we need to remove from an arraylist */
		arrayList.removeAll(Document.getStopWords());
		/* Making the array list unique */
		hashSet = new HashSet<String>(arrayList);
		/* Making a hash map of frequency of words */
		for (String str : hashSet) {
			hashMap.put(str, Collections.frequency(arrayList, str));
		}
		/* Removing the data in the objects */
		// System.out.println(arrayList);
		arrayList = new ArrayList<String>();
		// System.out.println(hashSet);
		hashSet = new HashSet<String>();
		/***********************************/
		// System.out.println(hashMap);
		return hashMap;
	}

	public static ArrayList<String> getStopWords() {
		return new ArrayList<String>(Arrays.asList("", "a", "about", "above",
				"above", "across", "after", "afterwards", "again", "against",
				"all", "almost", "alone", "along", "already", "also",
				"although", "always", "am", "among", "amongst", "amoungst",
				"amount", "an", "and", "another", "any", "anyhow", "anyone",
				"anything", "anyway", "anywhere", "are", "around", "as", "at",
				"back", "be", "became", "because", "become", "becomes",
				"becoming", "been", "before", "beforehand", "behind", "being",
				"below", "beside", "besides", "between", "beyond", "bill",
				"both", "bottom", "but", "by", "call", "can", "cannot", "cant",
				"co", "con", "could", "couldnt", "cry", "de", "describe",
				"detail", "do", "done", "down", "due", "during", "each", "eg",
				"eight", "either", "eleven", "else", "elsewhere", "empty",
				"enough", "etc", "even", "ever", "every", "everyone",
				"everything", "everywhere", "except", "few", "fifteen", "fify",
				"fill", "find", "fire", "first", "five", "for", "former",
				"formerly", "forty", "found", "four", "from", "front", "full",
				"further", "get", "give", "go", "had", "has", "hasnt", "have",
				"he", "hence", "her", "here", "hereafter", "hereby", "herein",
				"hereupon", "hers", "herself", "him", "himself", "his", "how",
				"however", "hundred", "ie", "if", "in", "inc", "indeed",
				"interest", "into", "is", "it", "its", "itself", "keep",
				"last", "latter", "latterly", "least", "less", "ltd", "made",
				"many", "may", "me", "meanwhile", "might", "mill", "mine",
				"more", "moreover", "most", "mostly", "move", "much", "must",
				"my", "myself", "name", "namely", "neither", "never",
				"nevertheless", "next", "nine", "no", "nobody", "none",
				"noone", "nor", "not", "nothing", "now", "nowhere", "of",
				"off", "often", "on", "once", "one", "only", "onto", "or",
				"other", "others", "otherwise", "our", "ours", "ourselves",
				"out", "over", "own", "part", "per", "perhaps", "please",
				"put", "rather", "re", "same", "see", "seem", "seemed",
				"seeming", "seems", "serious", "several", "she", "should",
				"show", "side", "since", "sincere", "six", "sixty", "so",
				"some", "somehow", "someone", "something", "sometime",
				"sometimes", "somewhere", "still", "such", "system", "take",
				"ten", "than", "that", "the", "their", "them", "themselves",
				"then", "thence", "there", "thereafter", "thereby",
				"therefore", "therein", "thereupon", "these", "they", "thickv",
				"thin", "third", "this", "those", "though", "three", "through",
				"throughout", "thru", "thus", "to", "together", "too", "top",
				"toward", "towards", "twelve", "twenty", "two", "un", "under",
				"until", "up", "upon", "us", "very", "via", "was", "we",
				"well", "were", "what", "whatever", "when", "whence",
				"whenever", "where", "whereafter", "whereas", "whereby",
				"wherein", "whereupon", "wherever", "whether", "which",
				"while", "whither", "who", "whoever", "whole", "whom", "whose",
				"why", "will", "with", "within", "without", "would", "yet",
				"you", "your", "yours", "yourself", "yourselves", "the"));
	}

	public static void insert(HashMap<String, Integer> hashMap, String fileURL) {
		String string;
		/* For Inserting into the word_index table */
		for (String str : hashMap.keySet()) {
			Database.insertIntoDatabase(Database.word_index_columns(),
					Database.word_index_table_name, "\'" + str + "\'");
		}
		/* For Inserting into the word_links table */
		for (String str : hashMap.keySet()) {
			string = Database.retrieveFromDatabase(
					Database.word_index_table_name_sno,
					Database.word_index_table_name,
					Database.word_index_table_name_word + "=\'" + str + "\'");
			if (string != null) {
				Database.insertIntoDatabase(Database.word_links_columns(),
						Database.word_link_table_name, string + ",\'" + fileURL
								+ "\'," + hashMap.get(str));
			}
		}
	}

	public static String[] tokenizeSearchTerm(String searchTerm) {
		return searchTerm.toLowerCase().trim().replaceAll("\\s+", " ")
				.split("\\s");
		/* replaceAll("\\W", "") */
	}

	/*
	 * This function will remove all the unnecessary things from the sentence
	 * gives a clean sentence
	 */
	public static String reformedSearchTerm(String searchTerm) {
		/* Spliting the string */
		String[] arrOfTerms = searchTerm.toLowerCase().trim()
				.replaceAll("\\s+", " ").split("\\s");
		searchTerm = "";
		/* Appending the string */
		for (int i = 0; i < arrOfTerms.length; i++) {
			searchTerm = searchTerm + arrOfTerms[i].replaceAll("\\W", "") + " ";
		}
		return searchTerm.trim();
	}

	/*
	 * This function will check the index and create a 2-d array so that we know
	 * in which all pages the word is present
	 */
	public static void booleanRetrievalSystem(String searchTerm,
			ArrayList<String> arrOfRecords, boolean twoDArray[][]) {
		/* Making the column */
		columnHashMap.put(searchTerm, columnCounter++);

		/* Filling up the row for the 2d array */
		for (String str : arrOfRecords) {
			/* if already the row is present then not added again */
			if (!rowHashMap.containsKey(str))
				rowHashMap.put(str, rowCounter++);
			twoDArray[rowHashMap.get(str).intValue()][columnHashMap.get(
					searchTerm).intValue()] = true;
		}
	}

	/* This function will display the 2d boolean array */
	public static void displayBooleanArray(boolean twoDArray[][]) {
		for (int i = 0; i < rowCounter; i++) {
			for (int j = 0; j < columnCounter; j++) {
				System.out.print(twoDArray[i][j] + "\t");
			}
			System.out.print("\n");
		}
	}

	/*
	 * This function was initially used so that we get only those links that
	 * contained all the words. The getAllSearchResults() below shows all the
	 * links but ranks them in an order of decreasing number of number of
	 * appearances of the term i.e if you are searching for
	 * "cheetah running spped" then it will first search for the documents that
	 * has all the three words, the the once that have only two and so on
	 */
	public static ArrayList<String> getResults(boolean twoDArray[][]) {
		ArrayList<String> searchResults = new ArrayList<String>();
		int allTrue = 0, i = 0, j = 0;
		for (i = 0; i < rowCounter; i++) {
			for (j = 0; j < columnCounter; j++) {
				if (twoDArray[i][j] == false) {
					allTrue = 0;
					break;
				}
				allTrue = 1;
			}
			if (allTrue == 1) {
				allTrue = 0;
				for (String str : rowHashMap.keySet()) {
					if (rowHashMap.get(str).intValue() == i) {
						searchResults.add(str);
						break;
					}
				}
			}
		}
		return searchResults;
	}

	/*
	 * This function will order the linke i.e it is doing the rank The
	 * getAllSearchResults() below shows all the links but ranks them in an
	 * order of decreasing number of number of appearances of the term i.e if
	 * you are searching for "cheetah running spped" then it will first search
	 * for the documents that has all the three words, the the once that have
	 * only two and so on
	 */
	@SuppressWarnings("unchecked")
	public static ArrayList<String> getAllSearchResults(boolean twoDArray[][]) {
		@SuppressWarnings("unused")
		ArrayList<String> searchResults = new ArrayList<String>();
		int counter = 0, i = 0, j = 0;
		for (i = 0; i < rowCounter; i++) {
			for (j = 0; j < columnCounter; j++) {
				if (twoDArray[i][j] == true)
					counter++;
			}
			/*
			 * e are counting the number of trues i each level and then storing
			 * it in an arraylist
			 */
			countOfNoOfTrues.put(i, counter);
			counter = 0;
		}
		// printHashMap(countOfNoOfTrues);
		System.out.println();
		/* Now we need to sort the hash map */
		countOfNoOfTrues = (HashMap<Integer, Integer>) sortHashMap(countOfNoOfTrues);
		// printHashMap(countOfNoOfTrues);
		return populateSearchResults();
	}

	/* To give all the search results and not just one search result */
	public static ArrayList<String> populateSearchResults() {
		ArrayList<String> searchResults = new ArrayList<String>();
		for (Integer i : countOfNoOfTrues.keySet()) {
			for (String str : rowHashMap.keySet()) {
				if (rowHashMap.get(str).intValue() == i.intValue()) {
					searchResults.add(str);
					break;
				}
			}
		}
		return searchResults;
	}

	/*
	 * This function will display the hash map whatever you will be passing to
	 * it. So no need of writing the 4 lines every time.
	 */
	public static void printHashMap(
			@SuppressWarnings("rawtypes") HashMap hashMap) {
		for (Object o : hashMap.keySet()) {
			System.out.print(String.valueOf(o) + "->"
					+ String.valueOf(hashMap.get(o)) + "\t");
		}
	}

	/*
	 * We need to sort the 2d boolean array such that the maximum number of true
	 * appear at the top then followed by the next maximum number of trues
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static Map sortHashMap(Map unsortedMap) {

		/* Get the values in a list */
		List list = new LinkedList(unsortedMap.entrySet());

		/* Sorting the list based on comparator */
		Collections.sort(list, new Comparator() {

			@Override
			public int compare(Object o1, Object o2) {
				return ((Comparable) ((Map.Entry) (o2)).getValue())
						.compareTo(((Map.Entry) (o1)).getValue());
			}
		});

		/* Now creating the sorted map */
		Map sortedMap = new LinkedHashMap();
		for (Iterator it = list.iterator(); it.hasNext();) {
			Map.Entry entry = (Map.Entry) it.next();
			sortedMap.put(entry.getKey(), entry.getValue());
		}

		return sortedMap;
	}

}
